package sugarcookie.assembler {
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.filesystem.File;
	import flash.filesystem.FileMode;
	import flash.filesystem.FileStream;
	import flash.html.HTMLLoader;
	import flash.net.URLRequest;
	
	import mx.collections.ArrayCollection;
	import mx.collections.ArrayList;
	import mx.collections.IViewCursor;
	import mx.logging.ILogger;
	import mx.logging.Log;
	import mx.utils.ObjectUtil;
	
	import sugarcookie.utils.ArrayUtil;
	import sugarcookie.utils.Observable;
	import sugarcookie.utils.StringUtil;
	
	public class AssemblyManager extends EventDispatcher {
		public static var ASSEMBLY_COMPLETE:String = "assemblyComplete";
		
		private var _log:ILogger;
		private var _isReady:Boolean = false;
		private var _waiting:Boolean = false;
		
		private var _paths:Array;
		private var _views:ArrayList;
		
		private var _bridge:HTMLLoader;
		private var _templateFile:FileStream;
		private var _template:XML;
		private var _xmlFile:FileStream;
		private var _xml:XML;
		private var _xsltFiles:ArrayCollection;
		private var _xsltFile:FileStream;
		private var _xslt:XML;
		private var _cursor:IViewCursor;
		private var _currView:String;
		
		private var finalFile:File;
		private var finalFileStream:FileStream;
		
		public function AssemblyManager() {
			super(this);
			_log = Log.getLogger("AssemblyManager");
			internal_init();
		}
		
		public function assemble(data:Array):void {
			_paths = data;
			if (!_isReady) {
				_waiting = true;
				return;
			}
			initAssembly();
		}
		
		private function internal_init():void {
			XML.ignoreComments = false;
			XML.prettyPrinting = false;
			XML.ignoreWhitespace = false;
			XML.prettyPrinting = false;
			
			_bridge = new HTMLLoader();
			var urlReq:URLRequest = new URLRequest("xslt_bridge.html");
			_bridge.addEventListener(Event.COMPLETE,bridgeLoadComplete);
			_bridge.load(urlReq);
		}
		
		private function bridgeLoadComplete(evt:Event):void {
			_bridge.removeEventListener(Event.COMPLETE,bridgeLoadComplete);
			_isReady = true;
			if (_waiting) {
				_waiting = false;
				initAssembly();
			}
		}
		
		private function initAssembly():void {
			_templateFile = new FileStream();
			_templateFile.addEventListener(Event.COMPLETE,templateLoaded);
			_templateFile.openAsync(getPath("template").file, FileMode.READ);
		}
		
		private function templateLoaded(evt:Event):void {
			_templateFile.removeEventListener(Event.COMPLETE,templateLoaded);
			_template = XML(FileStream(evt.target).readUTFBytes(FileStream(evt.target).bytesAvailable));
			
			_xmlFile = new FileStream();
			_xmlFile.addEventListener(Event.COMPLETE,dataLoadComplete);
			_xmlFile.openAsync(getPath("data").file, FileMode.READ);
		}
		
		private function dataLoadComplete(evt:Event):void {
			FileStream(evt.target).removeEventListener(Event.COMPLETE,dataLoadComplete);
			_xml = XML(FileStream(evt.target).readUTFBytes(FileStream(evt.target).bytesAvailable));
			
			var viewIds:Array = [];
			for (var i:int=0;i<_xml.view.length();i++) {
				var view:String = _xml.view[i].@id;
				viewIds.push({id:view,data:view});
			}
			_views = new ArrayList(viewIds);
			_xsltFiles = new ArrayCollection( getPath("xslt").file.getDirectoryListing() );
			_cursor = _xsltFiles.createCursor();
			
			loadXSLT();
		}
		
		private function loadXSLT():void {
			var regex:RegExp = /\/?[-a-zA-Z0-9_]+\.[a-z]{3}/;
			var path:String = _cursor.current.nativePath;
			
			var index:int = path.search(regex);
			if (index<0) {
				_cursor.moveNext();
				loadXSLT();
				return;
			} else {
				var fileId:String = path.substring(index+1, path.lastIndexOf("."));
				if (ArrayUtil.indexOfByPropValue(_views.source,"id",fileId) < 0) {
					_cursor.moveNext();
					loadXSLT();
					return;
				}
				_currView = fileId;
				_xsltFile = new FileStream();
				_xsltFile.addEventListener(Event.COMPLETE,xsltLoadComplete);
				_xsltFile.openAsync(File(_cursor.current), FileMode.READ);
			}
		}
		
		private function xsltLoadComplete(evt:Event):void {
			FileStream(evt.target).removeEventListener(Event.COMPLETE,xsltLoadComplete);
			_xslt = XML(FileStream(evt.target).readUTFBytes(FileStream(evt.target).bytesAvailable));
			
			var finalTemplate:XML = setNavSelection(_template.copy());
			var transformedXML:XML = XML(_bridge.window.transformXML(_xml.view.(@id==_currView),_xslt));
			
			finalTemplate..div.(@id=="content").setChildren(transformedXML.children());
			finalTemplate..div.(hasOwnProperty("@id") && @id=="content").@style = transformedXML.@style;
			
			finalTemplate.setNamespace(new Namespace("http://www.w3.org/1999/xhtml"));
			finalTemplate.@lang = "en-US";
			finalTemplate.@["xml:lang"] = "en-US";
			
			var finalHTML:String = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n'+finalTemplate;
			finalHTML = StringUtil.replaceAll(/\r/,finalHTML,"");
			
			//Now to save multiple files without a save dialog box
			finalFile = getPath("output").file;
			finalFile = finalFile.resolvePath(_currView+".html");
			finalFileStream = new FileStream();
			finalFileStream.openAsync(finalFile, FileMode.WRITE);
			finalFileStream.writeUTFBytes(finalHTML);
			finalFileStream.addEventListener(Event.CLOSE, fileClosed);
			finalFileStream.close();
		}
		
		private function fileClosed(event:Event):void {
			finalFileStream.removeEventListener(Event.CLOSE,fileClosed);
			_cursor.moveNext();
			if (!_cursor.afterLast) loadXSLT();
			else dispatchEvent(new Event(ASSEMBLY_COMPLETE));
		}
		
		private function setNavSelection(_tpl:XML):XML {
			var style:String = _tpl..div.(@id=="navigation").a.(@name==_currView).@style;
			style += "color:#F09A00;";
			_tpl..div.(@id=="navigation").a.(hasOwnProperty("@name") && @name==_currView).@style = style;
			return _tpl;
		}
		
		private function getPath(id:String):Object {
			return ArrayUtil.getItemByPropValue(_paths,"id",id);
		}
	}
}